﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

using AwesomeEnginePC.Physics;
using AwesomeEnginePC.Graphics.TwoDimensional.Sprites;

namespace AwesomeEnginePC.Graphics.TwoDimensional.Menus
{
	public enum InputDirection
	{
		Up = 0,
		Right,
		Down,
		Left,
	}
	
	public class MenuSystem
    {
		BaseSprite _background;
		List<MenuButton> _buttons;
		List<MenuLabel> _labels;
        ContentManager _cm;

        public MenuSystem(ContentManager cm)
        {
            _cm = cm;
            _buttons = new List<MenuButton>();
			_labels = new List<MenuLabel>();
        }

		public MenuSystem(ContentManager cm, BaseSprite background)
		{
			_cm = cm;
			_background = background;
			_buttons = new List<MenuButton>();
			_labels = new List<MenuLabel>();
		}

		/// <summary>
		/// Selects the First button (Keyboard or Xbox);
		/// If the interface is all mouse, then don't do this
		/// </summary>
		public void Init()
		{
			if (_buttons.Count > 0)
				_buttons.First().SelectButton();
			else
				throw new Exception("There must be atleast one button before you can Initialize the Menu System");
		}

        public void AddButton(MenuButton btn)
        {
			btn.Init();
			_buttons.Add(btn);
        }

		public void AddButton(MenuButton btn, string strName)
		{
			btn.Init(strName);
			_buttons.Add(btn);
		}

		public void AddLabel(MenuLabel lbl)
		{
			lbl.Init();
			_labels.Add(lbl);
		}

		public void AddLabel(MenuLabel lbl, string strName)
		{
			lbl.Init(strName);
			_labels.Add(lbl);
		}

		/// <summary>
		/// Looks for buttons that are some direction away from the currently selected button
		///  and then selects it only if it finds one
		/// </summary>
		/// <param name="direction"></param>
		public void SelectNextButton(InputDirection direction)
		{
			MenuButton currentButton = _buttons.Where((x) => x.buttonPress == false).First();
			MenuButton nextButton = null;
			
			switch (direction)
			{
				case InputDirection.Down:
					nextButton = GetClosestButtonDown(currentButton);
					break;
				case InputDirection.Left:
					nextButton = GetClosestButtonLeft(currentButton);
					break;
				case InputDirection.Right:
					nextButton = GetClosestButtonRight(currentButton);
					break;
				case InputDirection.Up:
					nextButton = GetClosestButtonUp(currentButton);
					break;
			}

			if (nextButton != null)
			{
				nextButton.SelectButton();
				currentButton.DeselectButton();
			}
		}

		private MenuButton GetClosestButtonUp(MenuButton currentButton)
		{
			MenuButton closestButton = null;
			
			foreach (var button in _buttons.Where((x) => x.Position.Y < currentButton.Position.Y))
			{
				if (closestButton == null)
				{
					closestButton = button;
				}

				if (GetAbsoluteDifference((int)currentButton.Position.Y, (int)button.Position.Y) < GetAbsoluteDifference((int)currentButton.Position.Y, (int)closestButton.Position.Y))
				{
					closestButton = button;
				}
			}

			return closestButton;
		}

		private MenuButton GetClosestButtonRight(MenuButton currentButton)
		{
			MenuButton closestButton = null;

			foreach (var button in _buttons.Where((x) => x.Position.X > currentButton.Position.X))
			{
				if (closestButton == null)
				{
					closestButton = button;
				}

				if (GetAbsoluteDifference((int)currentButton.Position.X, (int)button.Position.X) < GetAbsoluteDifference((int)currentButton.Position.X, (int)closestButton.Position.X))
				{
					closestButton = button;
				}
			}

			return closestButton;
		}

		private MenuButton GetClosestButtonLeft(MenuButton currentButton)
		{
			MenuButton closestButton = null;

			foreach (var button in _buttons.Where((x) => x.Position.X < currentButton.Position.X))
			{
				if (closestButton == null)
				{
					closestButton = button;
				}

				if (GetAbsoluteDifference((int)currentButton.Position.X, (int)button.Position.X) < GetAbsoluteDifference((int)currentButton.Position.X, (int)closestButton.Position.X))
				{
					closestButton = button;
				}
			}

			return closestButton;
		}

		private MenuButton GetClosestButtonDown(MenuButton currentButton)
		{
			MenuButton closestButton = null;

			foreach (var button in _buttons.Where((x) => x.Position.Y > currentButton.Position.Y))
			{
				if (closestButton == null)
				{
					closestButton = button;
				}

				if (GetAbsoluteDifference((int)currentButton.Position.Y, (int)button.Position.Y) < GetAbsoluteDifference((int)currentButton.Position.Y, (int)closestButton.Position.Y))
				{
					closestButton = button;
				}
			}

			return closestButton;
		}

		/// <summary>
		/// Get the Absolute Value Differnce between two integers
		/// </summary>
		/// <param name="X"></param>
		/// <param name="Y"></param>
		/// <returns></returns>
		private int GetAbsoluteDifference(int X, int Y)
		{
			int result = X - Y;

			if (result < 0)
				result *= -1;

			return result;
		}

		/// <summary>
		/// Presses the first Button that is being Hovered Over
		/// </summary>
		public void PressCurrentButton()
		{
			_buttons.Where((x) => x.buttonPress == false).First().PressButton();
		}

		/// <summary>
		/// Presses the First button with the provided name;
		///  Be careful with this, pressing more then one button too quickly can cause problems
		/// </summary>
		/// <param name="buttonName"></param>
		public void PressTargetButton(string buttonName)
		{
			_buttons.Where((x) => x._Name == buttonName).First().PressButton();
		}

		/// <summary>
		/// Selects the First button with the provided name;
		///  Be careful with this, selecting more then one button too quickly can cause problems
		/// </summary>
		/// <param name="buttonName"></param>
		public void SelectTargetButton(string buttonName)
		{
			_buttons.Where((x) => x._Name == buttonName).First().SelectButton();
		}

		public void DeselectTargetButton(string buttonName)
		{
			_buttons.Where((x) => x._Name == buttonName).First().DeselectButton();
		}

		/// <summary>
		/// Gets the currently pressed button's name and then sets that button to hovering,
		///  else returns an empty string
		/// </summary>
		/// <returns></returns>
		public string GetPressedButtonName()
		{
			string buttonName = "";
			MenuButton buttonTemp = null;
			
			buttonTemp = _buttons.Where((x) => x.buttonPress == true).FirstOrDefault();
			
			if(buttonTemp != null)
				buttonName = buttonTemp._Name;

			buttonTemp.SelectButton();

			return buttonName;
		}

		public void ChangeTargetLabelText(string targetName, string newText)
		{
			foreach (var label in _labels.Where((x) => x._Name == targetName))
			{
				label.ChangeDisplayText(newText);
			}
		}

		public void ChangeTargetButtonText(string targetName, string newText)
		{
			foreach (var button in _buttons.Where((x) => x._Name == targetName))
			{
				button.ChangeDisplayText(newText);
			}
		}

		//public void Draw
		public void Draw(GameTime gameTime, SpriteBatch SB)
		{
			if(_background != null)
				_background.Draw(gameTime, SB);
			
			foreach (var label in _labels)
			{
				label.Draw(gameTime, SB);
			}

			foreach (var button in _buttons)
			{
				button.Draw(gameTime, SB);
			}
		}
    }
}
